﻿using Blm.PgsqlDriver.Helpers;
using Blm.Utils.Extensions;
using Blm.Utils.Utility;
using Language.Resource;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Localization;
using Npgsql;
using Pipelines.Sockets.Unofficial.Arenas;
using System;
using System.Collections.Generic;
using System.Data;
using System.DrawingCore;
using System.DrawingCore.Drawing2D;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VisionCloud.Domain.Common;
using VisionCloud.Domain.DtoModel;
using VisionCloud.Domain.DtoModel.Ms;
using VisionCloud.Domain.DtoModel.Sys;
using VisionCloud.Domain.Repository.Interface.Ms;
using VisionCloud.Domain.Repository.Interface.Sys;
using VisionCloud.Utility;
using VisionCloud.Utility.Extensions;

namespace VisionCloud.Service.Ms
{
    /// <summary>
    /// 报告数据统计服务
    /// </summary>
    public class StatisService
    {
        public ICSMSTaskRepository CSMSTaskRepository { get; set; }

        public ISysUserRepository SysUserRepository { get; set; }

        public IStringLocalizer<ServiceResource> Localizer { get; set; }

        /// <summary>
        /// 测量服务服务器存储路径
        /// </summary>
        private readonly string measuringServicePath;

        /// <summary>
        /// 点云文件存储地址
        /// </summary>
        private readonly string taskDotCloudData;

        /// <summary>
        /// 文件服务器域名
        /// </summary>
        private static readonly string fileServer = ConfigHelper.GetValue<string>("FileServer");

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="option"></param>
        /// <param name="configuration"></param>
        public StatisService(IConfiguration configuration)
        {
            measuringServicePath = configuration.GetValue<string>("MeasuringService");
            taskDotCloudData = configuration.GetValue<string>("TaskDotCloudData");
        }

        /// <summary>
        /// 作者：黄钧航
        /// 根据项目Id、楼栋号和楼层信息获取点云和户型图数据
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        public async Task<List<MeasuringTask>> GetPointCloudData(MsCondition condition)
        {
            if (string.IsNullOrWhiteSpace(condition.ProjectId))
            {
                throw new OperationException(Localizer["YB0008"].Value);
            }

            if (string.IsNullOrWhiteSpace(condition.Build))
            {
                condition.Build = string.Empty;
            }

            if (string.IsNullOrWhiteSpace(condition.Floor))
            {
                condition.Floor = string.Empty;
            }

            List<NpgsqlParameter> parameters = new List<NpgsqlParameter>
            {
                new NpgsqlParameter("@ProjectId",condition.ProjectId.ToGuid()),
                new NpgsqlParameter("@BuildingName",condition.Build),
                new NpgsqlParameter("@FloorName", condition.Floor)
            };

            string sql = string.Format(VisionCloudGlobalContext.GetSection("sqls:sql:query_point_cloud_data"));

            var measuringTasks = await PgSqlHelper.QueryListAsync<MeasuringTask>(sql, parameters.ToArray());
            foreach (var item in measuringTasks)
            {
                item.PointClouds = GetPointCloudFile(item.ProjectNo, item.TaskId);
                item.TaskHouseMapUrl = GetTaskHouseMap(item.TaskId, item.TaskName);
            }

            return measuringTasks;
        }

        /// <summary>
        /// 作者：黄钧航
        /// 上传实测点云经过算法计算后生成资源文件
        /// </summary>
        /// <param name="formCollection"></param>
        /// <returns></returns>
        public async Task<List<string>> UploadMeasuringSourceData(IFormCollection formCollection)
        {
            string excelDirectory = string.Empty;
            string filePath = string.Empty;
            string unzipFolder = string.Empty;
            string dirPath2 = string.Empty;
            string dirPath = string.Empty;
            string fileName = string.Empty;
            string msg = string.Empty;
            try
            {
                // 校验逻辑

                if (formCollection.Count == 0)
                {
                    throw new OperationException(Localizer["YB0287"].Value);
                }

                if (formCollection.Keys.Count == 0)
                {
                    throw new OperationException(Localizer["YB0171"].Value);
                }

                if (!formCollection.ContainsKey("path"))
                {
                    throw new OperationException(Localizer["YB0172"].Value);
                }

                string subprefix = formCollection["path"][0];
                if (string.IsNullOrWhiteSpace(subprefix))
                {
                    throw new OperationException(Localizer["YB0172"].Value);
                }

                long size = formCollection.Files.Sum(f => f.Length);  // BYTE

                // 一次上传文件不能超过500M
                if (size / 1024 / 1024 > 500)
                {
                    throw new OperationException(Localizer["YB0174"].Value);
                }

                foreach (IFormFile formFile in formCollection.Files)
                {
                    if (formFile.Length == 0)
                    {
                        throw new OperationException(Localizer["YB0287"].Value);
                    }

                    string fileExtension = Path.GetExtension(formFile.FileName);              // 压缩文件名称
                    if (!string.Equals(fileExtension, ".png", StringComparison.OrdinalIgnoreCase)
                        && !string.Equals(fileExtension, ".jpg", StringComparison.OrdinalIgnoreCase)
                        && !string.Equals(fileExtension, ".json", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new OperationException(Localizer["YB0175"].Value);
                    }
                    fileName = formFile.FileName.Replace(fileExtension, string.Empty);        // 扩展名

                    // 创建文件

                    dirPath2 = $"{taskDotCloudData}/measuringdata/source";  // TODO:通过配置文件获取路径
                    dirPath = $"{dirPath2}/{subprefix}";  // TODO:通过配置文件获取路径
                    Logger.Info($"UploadMeasuringSourceData：{filePath}");

                    // 拷贝文件到目标路径
                    using (formFile.OpenReadStream())
                    {
                        if (!Directory.Exists(dirPath)) Directory.CreateDirectory(dirPath);
                        filePath = Path.Combine(dirPath, formFile.FileName);
                        using (FileStream fileStream = new FileStream(filePath, FileMode.Create))
                        {
                            formFile.CopyTo(fileStream);
                        }
                    }

                    if (!File.Exists(filePath))
                    {
                        msg = string.Format(Localizer["YB0175"].Value, filePath);
                        Logger.Error(msg);
                        throw new OperationException(msg);
                    }
                }

                // 生成文件URL

                List<string> files = new List<string>();
                unzipFolder = dirPath;
                Logger.Info($"unzipFolder：{unzipFolder}");

                FileInfoUtil.GetAllFiles(unzipFolder, files);
                if (files.Count == 0)
                {
                    msg = Localizer["YB0177"].Value;
                    Logger.Error(msg);
                    throw new OperationException(msg);
                }
                List<string> urls = new List<string>();
                foreach (var item in files)
                {
                    urls.Add(ToTaskPointCloudUrl(item)); // 图片资源文件Url
                }
                return urls;
            }
            catch (Exception ex)
            {
                msg = ex.Message.ToString();
                Logger.Error(msg);
                throw new OperationException(Localizer["YB0178"].Value);
            }
        }

        /// <summary>
        /// 根据任务编号获取站点和墙面点云文件信息
        /// </summary>
        /// <param name="projectNo">项目编号</param>
        /// <param name="taskId">任务Id</param>
        /// <returns></returns>
        private List<MeasuringStation> GetPointCloudFile(string projectNo, string taskId)
        {
            string dirPath = $"{taskDotCloudData}";

            if (!Directory.Exists(dirPath))       // 点云存储文件夹不存在
            {
                Directory.CreateDirectory(dirPath);
                return null;
            }

            var files = new List<string>();
            // 兼容未压缩文件
            FileInfoUtil.GetAllFiles(dirPath, files, taskId, "pcd");
            // 获取压缩后点云
            var files2 = new List<string>();
            FileInfoUtil.GetAllFiles(dirPath, files2, taskId, "gz");
            if (files2 != null && files2.Count != 0)
            {
                foreach (var item in files2)
                {
                    files.Add(item);
                }
            }
            if (files.Count == 0)
            {
                Logger.Info($"任务{taskId}没有点云文件");
                return null;
            }

            files.Sort((a, b) =>
            {
                int c = string.Compare(a, b);
                return c;
            });
            List<MeasuringStation> measuringStations = new List<MeasuringStation>();
            foreach (var file in files)
            {
                var fileInfo = new FileInfo(file);
                var nameArray = fileInfo.Name.Split("_");
                string index = string.Empty;
                if (nameArray.Length != 0)
                {
                    // 对应站点编号
                    index = nameArray[nameArray.Length - 1].Replace(fileInfo.Extension, string.Empty);
                    if (index.Contains(".pcd", StringComparison.OrdinalIgnoreCase))
                    {
                        index = index.Replace(".pcd", string.Empty, StringComparison.OrdinalIgnoreCase);
                    }
                }

                var existedPcdData = measuringStations.Find(x => x.Index == index);    // 判断同一个站点是否有多个点云数据，如有只取最新的；
                if (existedPcdData != null)
                {
                    existedPcdData.Url = ToTaskPointCloudUrl(file);  // 点云Url
                    existedPcdData.FileName = fileInfo.Name;
                }
                else
                {
                    var measuringStation = new MeasuringStation()
                    {
                        Url = ToTaskPointCloudUrl(file),  // 点云Url
                        Index = index,                    // 站点序号
                        FileName = fileInfo.Name,         // 点云文件名称
                    };
                    measuringStations.Add(measuringStation);
                }
            }

            if (measuringStations.Count == 0)             // 没有实测点云就不用找墙面点云
            {
                return measuringStations;
            }

            #region 获取墙面点云数据

            var pcdData = measuringStations.ToJsonStr().ToObject<List<MeasuringStation>>();  // 复制当前列表
            dirPath = $"{measuringServicePath}/measuring-wall-data";
            string wallFilesFolder = Path.Combine(dirPath, taskId);
            if (Directory.Exists(wallFilesFolder))
            {
                var wallFiles = new List<string>();
                FileInfoUtil.GetAllFiles(wallFilesFolder, wallFiles, taskId);   // 递归获取对应点云文件
                if (wallFiles.Count != 0)
                {
                    foreach (var file in wallFiles)
                    {
                        var fileInfo = new FileInfo(file);

                        if (!pcdData.Exists(x =>
                            fileInfo.Name.Contains(x.FileName.Substring(0, x.FileName.IndexOf(".")))))              // 找和实测点云文件名匹配的墙面点云文件
                        {
                            continue;
                        }
                        var nameArray = fileInfo.Name.Split("_");
                        string index = string.Empty;
                        if (nameArray.Length != 0)
                        {
                            // 对应站点编号
                            index = $"{nameArray[nameArray.Length - 2]}_{nameArray[nameArray.Length - 1].Substring(0, nameArray[nameArray.Length - 1].IndexOf("."))}";
                        }

                        var measuringStation = new MeasuringStation()
                        {
                            Url = ToMeasuringServiceUrl(file),  // 点云Url
                            Index = index,                    // 站点序号
                            FileName = fileInfo.Name,         // 点云文件名称
                        };
                        measuringStations.Add(measuringStation);
                    }
                }
            }

            #endregion 获取墙面点云数据

            #region V4.3版本墙面点云存储结构调整

            //var pcdData = measuringStations.ToJsonStr().ToObject<List<MeasuringStation>>();  // 复制当前列表
            dirPath = $"{measuringServicePath}/DataFile/{projectNo.Replace("-", "/")}";
            wallFilesFolder = Path.Combine(dirPath, taskId, "measuring-wall-data");
            if (Directory.Exists(wallFilesFolder))
            {
                var wallFiles = new List<string>();
                FileInfoUtil.GetAllFiles(wallFilesFolder, wallFiles, taskId);   // 递归获取对应点云文件
                if (wallFiles.Count != 0)
                {
                    foreach (var file in wallFiles)
                    {
                        var fileInfo = new FileInfo(file);

                        if (!pcdData.Exists(x =>
                            fileInfo.Name.Contains(x.FileName.Substring(0, x.FileName.IndexOf(".")))))              // 找和实测点云文件名匹配的墙面点云文件
                        {
                            continue;
                        }
                        var nameArray = fileInfo.Name.Split("_");
                        string index = string.Empty;
                        if (nameArray.Length != 0)
                        {
                            // 对应站点编号
                            index = $"{nameArray[nameArray.Length - 2]}_{nameArray[nameArray.Length - 1].Substring(0, nameArray[nameArray.Length - 1].IndexOf("."))}";
                        }

                        var measuringStation = new MeasuringStation()
                        {
                            Url = ToMeasuringServiceUrl(file),  // 点云Url
                            Index = index,                    // 站点序号
                            FileName = fileInfo.Name,         // 点云文件名称
                        };
                        measuringStations.Add(measuringStation);
                    }
                }
            }

            #endregion V4.3版本墙面点云存储结构调整

            return measuringStations;
        }

        /// <summary>
        /// 作者：黄钧航
        /// 根据任务Id获取对应任务户型图
        /// </summary>
        /// <param name="taskId">任务id</param>
        /// <param name="taskName">任务名称</param>
        /// <returns></returns>
        private string GetTaskHouseMap(string taskId, string taskName)
        {
            Logger.Info($"GetTaskHouseMap：开始");

            var taskIdGuid = taskId.ToGuid();
            var info = CSMSTaskRepository.FirstOrDefault(p => p.TaskId == taskIdGuid);
            if (string.IsNullOrWhiteSpace(info.ResultDataFilePath))
                return string.Empty;

            string dirPath = Path.Combine(info.ResultDataFilePath, taskName, "任务户型图");

            Logger.Info(dirPath);
            if (!Directory.Exists(dirPath))
            {
                return string.Empty;
            }

            var files = Directory.GetFiles(dirPath);
            return ToTaskReportUrl(files[0], false);
        }

        /// <summary>
        /// 获取用户的项目信息
        /// </summary>
        /// <param name="condition"></param>
        /// <param name="isDelete"></param>
        /// <returns></returns>
        public async Task<List<ProjectInfoDto>> GetUserProjectInfo(UserProjectStatisDto condition, bool? isDelete = null)
        {
            List<ProjectInfoDto> list = new List<ProjectInfoDto>();
            Dictionary<Guid, string> projectInfoDic = new Dictionary<Guid, string>();
            List<NpgsqlParameter> parameters = new List<NpgsqlParameter>();
            StringBuilder sb = new StringBuilder();
            string IsCanPullStr = condition.IsCanPull.HasValue ? $@" and t1.""IsCanPull"" = {condition.IsCanPull.Value}" : "";

            var user = await SysUserRepository.GetUser(new SysUserDto { YunUserGuid = OperatorProvider.Get().Id, Code = OperatorProvider.Get().UserCode });
            if (user != null && user.RoleNameList.Contains("公司管理员") && condition.YunUserGuid == OperatorProvider.Get().Id)//公司管理员，直接从表里取数据
            {
                string componyGuid = user.SysOrgId;
                condition.YunUserGuid = Guid.Empty;

                var sql = $@"select ""ProjectId"",""Name"" as ""ProjectName"",""ProjectVersion"",""IsCanPull"" from ""MsProject"" t1 where t1.""CompanyGuid""='{componyGuid}' ";
                if (isDelete.HasValue)
                    sql += $@" and  t1.""IsDeleted""={isDelete.Value}{IsCanPullStr} ";

                sb.AppendLine(sql);
            }
            else
            {
                if (isDelete.HasValue)
                    sb.AppendLine($@"select * from vw_user_project_info t1 where t1.""IsDeleted""={isDelete.Value}{IsCanPullStr}");
                else
                    sb.AppendLine("select * from vw_user_project_info t1 where 1=1 ");
            }
            GetSql<UserProjectStatisDto>(condition, parameters, sb);

            var versionDtos = await PgSqlHelper.QueryListAsync<ProjectVersionDto>(sb.ToString(), parameters.ToArray());
            foreach (var item in versionDtos)
            {
                if (!projectInfoDic.ContainsKey(item.ProjectId))
                {
                    projectInfoDic.Add(item.ProjectId, item.ProjectName);
                    ProjectInfoDto projectInfoDto = new ProjectInfoDto();
                    projectInfoDto.ProjectId = item.ProjectId;
                    projectInfoDto.ProjectName = item.ProjectName;
                    projectInfoDto.ProjectVersion = item.ProjectVersion;
                    projectInfoDto.IsCanPull = item.IsCanPull;
                    list.Add(projectInfoDto);
                }
            }

            return list;
        }

        /// <summary>
        /// 获取最新的消息，并且把消息设置为已读
        /// </summary>
        /// <returns></returns>
        public async Task<NewMessage[]> GetNewMessage()
        {
            List<NpgsqlParameter> parameters = new List<NpgsqlParameter>
            {
                new NpgsqlParameter("@UserId", OperatorProvider.Get()?.YunUserGuid)
            };

            string selectSql = string.Format(VisionCloudGlobalContext.GetSection("sqls:sql:query_new_message"));
            var messages = await PgSqlHelper.QueryListAsync<NewMessage>(selectSql, parameters.ToArray());

            if (messages != null && messages.Count() > 0)
            {
                var ids = "'" + string.Join("',\'", messages.Select(i => i.CSUser2TaskInfoGuid.ToString()).ToArray()) + "'";
                var updateSql = $@"update ""CSUser2TaskInfo"" set ""IsPullMessageToUser""=true where ""CSUser2TaskInfoGuid"" in ({ids}) ; ";
                await PgSqlHelper.ExecuteNonQueryAsync(CommandType.Text, updateSql);
            }
            return messages.ToArray();
        }

        /// <summary>
        /// 设置当前用户已经读取这个字段
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        public async Task<bool> UserIsReadedTask(UserIsReadedTaskDto condition)
        {
            if (condition.TaskId == Guid.Empty)
            {
                throw new OperationException(Localizer["YB0189"].Value);
            }

            List<NpgsqlParameter> parameters = new List<NpgsqlParameter>
            {
                new NpgsqlParameter("@TaskId", condition.TaskId),
                new NpgsqlParameter("@UserId", OperatorProvider.Get()?.YunUserGuid)
            };

            string selectSql = string.Format(VisionCloudGlobalContext.GetSection("sqls:sql:query_user_is_readed_task01"));
            var total = await PgSqlHelper.QueryScalarAsync<long>(selectSql, parameters.ToArray());
            int affrows;
            if (total > 0)
            {
                string updateSql = string.Format(VisionCloudGlobalContext.GetSection("sqls:sql:query_user_is_readed_task02"));
                affrows = await PgSqlHelper.ExecuteNonQueryAsync(CommandType.Text, updateSql, parameters.ToArray());
                return affrows > 0;
            }

            parameters.Add(new NpgsqlParameter("@CSUser2TaskInfoGuid", Guid.NewGuid()));
            parameters.Add(new NpgsqlParameter("@CreatedBy", Guid.Empty));
            parameters.Add(new NpgsqlParameter("@CreatedDate", DateTime.Now));
            parameters.Add(new NpgsqlParameter("@LastUpdatedBy", Guid.Empty));
            parameters.Add(new NpgsqlParameter("@LastUpdatedDate", DateTime.Now));

            string insertSql = string.Format(VisionCloudGlobalContext.GetSection("sqls:sql:query_user_is_readed_task03"));

            affrows = await PgSqlHelper.ExecuteNonQueryAsync(CommandType.Text, insertSql, parameters.ToArray());
            return affrows > 0;
        }

        /// <summary>
        /// 获取项目分析数据
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        public async Task<QualityAnalysisChartDto> GetProjectStatis(ReportStatisDto condition)
        {
            QualityAnalysisChartDto qualityAnalysisChartDto = new QualityAnalysisChartDto();

            #region 初测统计

            QualityAnalysisChartItem qualityAnalysisChartItem = new QualityAnalysisChartItem();
            qualityAnalysisChartItem.StageName = "初测";
            condition.TaskProperty = qualityAnalysisChartItem.StageName;
            qualityAnalysisChartItem = GetReportStatis(condition);
            qualityAnalysisChartDto.Items.Add(qualityAnalysisChartItem);

            #endregion 初测统计

            #region 复测统计

            qualityAnalysisChartItem = new QualityAnalysisChartItem();
            qualityAnalysisChartItem.StageName = "复测";
            condition.TaskProperty = qualityAnalysisChartItem.StageName;
            qualityAnalysisChartItem = GetReportStatis(condition);
            qualityAnalysisChartDto.Items.Add(qualityAnalysisChartItem);

            #endregion 复测统计

            #region 排序

            if (string.IsNullOrEmpty(condition.OrderBy))
            {
                condition.OrderBy = "初测";
            }

            List<BuildingData> buildingDatas = null;//依据数据组
            List<BuildingData> buildingDatas1 = null;//重拍数据组
            if (condition.OrderBy == "初测")
            {
                buildingDatas = qualityAnalysisChartDto.Items[0].BuildingData;
                buildingDatas1 = qualityAnalysisChartDto.Items[1].BuildingData;
            }
            else
            {
                buildingDatas = qualityAnalysisChartDto.Items[1].BuildingData;
                buildingDatas1 = qualityAnalysisChartDto.Items[0].BuildingData;
            }

            #region 并集buildingData数据

            foreach (var buildingData in buildingDatas)//测量项
            {
                for (int i = 0; i < buildingData.XAxis.Count; i++)
                {
                    var tempBuildingData = buildingDatas1.Where(p => p.Code == buildingData.Code).FirstOrDefault();
                    if (tempBuildingData != null)
                    {
                        if (!tempBuildingData.XAxis.Contains(buildingData.XAxis[i]))
                        {
                            tempBuildingData.XAxis.Add(buildingData.XAxis[i]);
                            tempBuildingData.PassPercent.Add("");
                        }
                    }
                }
            }

            foreach (var buildingData in buildingDatas1)//测量项
            {
                for (int i = 0; i < buildingData.XAxis.Count; i++)
                {
                    var tempBuildingData = buildingDatas.Where(p => p.Code == buildingData.Code).FirstOrDefault();
                    if (tempBuildingData != null)
                    {
                        if (!tempBuildingData.XAxis.Contains(buildingData.XAxis[i]))
                        {
                            tempBuildingData.XAxis.Add(buildingData.XAxis[i]);
                            tempBuildingData.PassPercent.Add("");
                        }
                    }
                }
            }

            #endregion 并集buildingData数据

            #region 排序

            foreach (var buildingData in buildingDatas)//测量项
            {
                #region 排序依据数据组的结果

                List<XAxisData> dataList = new List<XAxisData>();
                for (int i = 0; i < buildingData.XAxis.Count; i++)
                {
                    XAxisData xAxisData = new XAxisData();
                    xAxisData.XAxis = buildingData.XAxis[i].ToString();
                    xAxisData.Vaule = buildingData.PassPercent[i].ToDecimal();

                    dataList.Add(xAxisData);
                }

                dataList = dataList.OrderBy(p => p.XAxis).ToList();

                var orderList = dataList.OrderByDescending(p => p.Vaule).ToList();
                buildingData.PassPercent = dataList.OrderByDescending(p => p.Vaule).Select(p1 => p1.Vaule.ToString()).ToList();
                buildingData.XAxis = dataList.OrderByDescending(p => p.Vaule).Select(p1 => p1.XAxis).ToList();

                #endregion 排序依据数据组的结果

                #region 根据依据数据组的排序结果排序重拍数据组的结果

                var buildingData1 = buildingDatas1.Where(p => p.Code == buildingData.Code).FirstOrDefault();
                if (buildingData1 != null)
                {
                    if (buildingData1.XAxis.Count > 0)
                    {
                        List<XAxisData> dataList1 = new List<XAxisData>();
                        for (int i = 0; i < buildingData1.XAxis.Count; i++)
                        {
                            XAxisData xAxisData = new XAxisData();
                            xAxisData.XAxis = buildingData1.XAxis[i].ToString();
                            xAxisData.Vaule = buildingData1.PassPercent[i].ToDecimal();

                            dataList1.Add(xAxisData);
                        }

                        List<XAxisData> orderList2 = new List<XAxisData>();
                        for (int i = 0; i < orderList.Count; i++)
                        {
                            var dest = dataList1.Where(p => p.XAxis == orderList[i].XAxis).FirstOrDefault();
                            if (dest != null)
                            {
                                orderList2.Add(dest);
                            }
                            else
                            {
                                XAxisData xAxisData = new XAxisData();
                                xAxisData.XAxis = orderList[i].XAxis;
                                xAxisData.Vaule = null;
                                orderList2.Add(xAxisData);
                            }
                        }

                        buildingData1.PassPercent = orderList2.Select(p1 => p1.Vaule.ToString()).ToList();
                        buildingData1.XAxis = orderList2.Select(p1 => p1.XAxis).ToList();
                    }
                }

                #endregion 根据依据数据组的排序结果排序重拍数据组的结果
            }

            #endregion 排序

            #endregion 排序

            return qualityAnalysisChartDto;
        }

        /// <summary>
        /// 作者：黄钧航
        /// 生成站点报告二维码
        /// </summary>
        /// <param name="filesPath">图片源路径</param>
        /// <param name="barcodePath">二维码保存路径</param>
        /// <param name="title">报告名称</param>
        public void CreateBarcode(string[] filesPath, string barcodePath, string title)
        {
            foreach (var filePath in filesPath)
            {
                #region 生成二维码图片

                FileInfo file = new FileInfo(filePath);
                string fileName = file.Name.Replace(file.Extension, string.Empty);  // 无后缀文件名
                string qrCodeFileSave = Path.Combine(barcodePath, $"{fileName}.png");
                string qrCodeUrl = filePath;  // 文件服务器物理路径

                string reportName = title;
                string pointIndex = fileName.Replace("测量站点", string.Empty).Replace("测量报告", string.Empty);
                string reqUrl = ToTaskReportUrl(qrCodeUrl);
                int width = 0;
                int height = 0;
                string tempDir = Path.Combine(AppContext.BaseDirectory, "temp");
                if (!Directory.Exists(tempDir))
                {
                    Directory.CreateDirectory(tempDir);
                }
                string tempFileName = Path.Combine(tempDir, Guid.NewGuid().ToString() + ".png");
                var qrHelper = new QRCoderHelper();
                using (var qrCoderBitMap = qrHelper.GetQRCode(reqUrl, 7))
                {
                    width = qrCoderBitMap.Width;
                    height = qrCoderBitMap.Height;

                    qrCoderBitMap.Save(tempFileName);
                }

                #endregion 生成二维码图片

                using (var qrCoderBitMap = new Bitmap(tempFileName))
                {
                    using (var bitMap = new Bitmap(width + 300, height + 50))
                    {
                        using (Graphics mygraphics = Graphics.FromImage(bitMap))
                        {
                            //字体
                            int fontSize = 12;
                            using (Font font = new Font("宋体", fontSize, FontStyle.Bold))
                            {
                                mygraphics.SmoothingMode = SmoothingMode.AntiAlias;

                                #region 标题

                                var pointF = new Point();
                                pointF.X = (bitMap.Width - width) / 2;
                                using (Brush blackBrush = new SolidBrush(Color.Black))
                                {
                                    SizeF sizeF = mygraphics.MeasureString(reportName, font);
                                    int xFloat = (bitMap.Width - (int)sizeF.Width) / 2;
                                    // 标题一
                                    mygraphics.DrawString($"{reportName}", font, blackBrush, xFloat, 2);
                                    string pointNoInfo = $"站点编号: {pointIndex}";
                                    sizeF = mygraphics.MeasureString(pointNoInfo, font);
                                    xFloat = (bitMap.Width - (int)sizeF.Width) / 2;
                                    // 标题二
                                    mygraphics.DrawString(pointNoInfo, font, blackBrush, xFloat, 2 + fontSize * 2);
                                    pointF.Y = 8 + (int)sizeF.Height * 2;
                                }

                                // 二维码
                                mygraphics.DrawImage(qrCoderBitMap, pointF);
                                bitMap.Save(qrCodeFileSave);

                                #endregion 标题
                            }
                        }
                    }
                }

                // 删除临时文件
                File.Delete(tempFileName);
            }
        }

        /// <summary>
        /// 点云文件压缩包URL
        /// </summary>
        /// <param name="relativePath"></param>
        /// <returns></returns>
        public static string ToDotCloudUrl(string relativePath)
        {
            string flag = "task-report-data";
            relativePath = relativePath.Replace(@"\", "/");
            int pIndex = relativePath.IndexOf(flag);
            if (pIndex > -1)
            {
                relativePath = relativePath.Substring(pIndex + flag.Length);
            }
            return $"{fileServer}/" + relativePath + "/";
        }

        /// <summary>
        /// 任务报告URL
        /// </summary>
        /// <param name="relativePath"></param>
        /// <param name="isTaskData"></param>
        /// <returns></returns>
        public static string ToTaskReportUrl(string relativePath, bool isTaskData = false)
        {
            if (!isTaskData)
            {
                string flag = "task-report-data";
                relativePath = relativePath.Replace(@"\", "/");
                int pIndex = relativePath.IndexOf(flag);
                if (pIndex > -1)
                {
                    relativePath = relativePath.Substring(pIndex + flag.Length);
                }
                return $"{fileServer}/taskreport" + relativePath;
            }
            else
            {
                string flag = "task-data-backup";
                relativePath = relativePath.Replace(@"\", "/");
                int pIndex = relativePath.IndexOf(flag);
                if (pIndex > -1)
                {
                    relativePath = relativePath.Substring(pIndex + flag.Length);
                }
                return $"{fileServer}/taskdata" + relativePath;
            }
        }

        /// <summary>
        /// 点云文件URL
        /// </summary>
        /// <param name="relativePath"></param>
        /// <returns></returns>
        private string ToTaskPointCloudUrl(string relativePath)
        {
            string flag = "task-dotcloud-data";
            relativePath = relativePath.Replace(@"\", "/");
            int pIndex = relativePath.IndexOf(flag);
            if (pIndex > -1)
            {
                relativePath = relativePath.Substring(pIndex + flag.Length);
            }
            return $"{fileServer}/taskdotclouddata" + relativePath;
        }

        /// <summary>
        /// 墙面点云URL
        /// </summary>
        /// <param name="relativePath"></param>
        /// <returns></returns>
        private string ToMeasuringServiceUrl(string relativePath)
        {
            string flag = "measuring-service";
            relativePath = relativePath.Replace(@"\", "/");
            int pIndex = relativePath.IndexOf(flag);
            if (pIndex > -1)
            {
                relativePath = relativePath.Substring(pIndex + flag.Length);
            }
            return $"{fileServer}/measuringservice" + relativePath;
        }

        /// <summary>
        /// 获取报告统计分析
        /// </summary>
        /// <param name="condition"></param>
        /// <returns></returns>
        /// <exception cref="OperationException"></exception>
        private QualityAnalysisChartItem GetReportStatis(ReportStatisDto condition)
        {
            #region 必填项验证

            if (string.IsNullOrEmpty(condition.ProjectName))
            {
                throw new OperationException(Localizer["YB0195"].Value);
            }

            if (string.IsNullOrEmpty(condition.TaskProperty))
            {
                throw new OperationException(Localizer["YB0196"].Value);
            }

            #endregion 必填项验证

            QualityAnalysisChartItem qualityAnalysisChartItem = new QualityAnalysisChartItem();
            qualityAnalysisChartItem.StageName = condition.TaskProperty;

            List<NpgsqlParameter> parameters = new List<NpgsqlParameter>();
            StringBuilder sb = new StringBuilder();
            sb.AppendLine($@"select * from ""MsDataStatistics"" t1 join ""CSMSTask"" t2 on t2.""TaskId"" = t1.""TaskId"" where t2.""IsDeleteReport"" = FALSE ");
            GetSql<ReportStatisDto>(condition, parameters, sb);

            TotalPass totalPass = new TotalPass();
            qualityAnalysisChartItem.TotalPass = totalPass;

            // 构造测量项统计项
            List<MeasureItemData> measureItemDataList = new List<MeasureItemData>();
            foreach (var el in GetDicItem)
            {
                MeasureItemData measureItemData = new MeasureItemData();
                measureItemData.Code = el.Key;
                measureItemData.Title = el.Value;
                measureItemData.PassPercent = new List<string>();//只有一个值，列表扩展保留
                measureItemDataList.Add(measureItemData);
            }
            qualityAnalysisChartItem.MeasureItemData = measureItemDataList;

            // 构造楼栋合格率的统计项
            List<BuildingData> buildingDataList = new List<BuildingData>();
            foreach (var el in GetDicItem)
            {
                BuildingData buildingData = new BuildingData();
                buildingData.Code = el.Key;
                buildingData.Title = el.Value;
                buildingData.PassPercent = new List<string>();
                buildingData.XAxis = new List<string>();
                buildingDataList.Add(buildingData);
            }
            qualityAnalysisChartItem.BuildingData = buildingDataList;

            using (DataSet ds = PgSqlHelper.ExecuteDataSet(sb.ToString(), parameters.ToArray()))
            {
                if (ds != null && ds.Tables.Count > 0)
                {
                    var dt = ds.Tables[0];

                    #region 综合合格率

                    foreach (DataRow dr in dt.Rows)
                    {
                        foreach (var measureItemData in measureItemDataList)
                        {
                            totalPass.PassNum += (dr[measureItemData.Code + "_C"].ToInt32() - dr[measureItemData.Code + "_P"].ToInt32());
                            totalPass.FailureNum += dr[measureItemData.Code + "_P"].ToInt32();
                        }
                    }

                    #endregion 综合合格率

                    #region 测量项合格率

                    GetMeasureItemStatis(measureItemDataList, dt);

                    #endregion 测量项合格率

                    #region 楼栋合格率

                    foreach (var buildingData in buildingDataList)
                    {
                        #region 从最小维度开始往上

                        if (!string.IsNullOrEmpty(condition.FloorName))
                        {
                            //项目-楼栋-楼层 按户型统计
                            GetFloorLevelStatis(dt, buildingData, condition.ProjectName, condition.BuildingName, condition.FloorName);
                        }
                        else if (!string.IsNullOrEmpty(condition.BuildingName))
                        {
                            //项目-楼栋 按楼层统计
                            GetBuildingLevelStatis(dt, buildingData, condition.ProjectName, condition.BuildingName);
                        }
                        else if (!string.IsNullOrEmpty(condition.ProjectName))
                        {
                            //项目 按楼栋统计
                            GetProjectLevelStatis(dt, buildingData, condition.ProjectName);
                        }

                        #endregion 从最小维度开始往上
                    }

                    #endregion 楼栋合格率
                }
            }

            return qualityAnalysisChartItem;
        }

        /// <summary>
        /// 计算测量项统计信息
        /// </summary>
        /// <param name="measureItemDataList"></param>
        /// <param name="dt"></param>
        private static void GetMeasureItemStatis(List<MeasureItemData> measureItemDataList, DataTable dt)
        {
            foreach (var measureItemData in measureItemDataList)
            {
                foreach (DataRow dr in dt.Rows)
                {
                    measureItemData.CNum += dr[measureItemData.Code + "_C"].ToInt32();
                    measureItemData.PNum += dr[measureItemData.Code + "_P"].ToInt32();
                }

                if (measureItemData.CNum > 0)
                {
                    decimal passRate = (decimal)(measureItemData.CNum - measureItemData.PNum) / (decimal)measureItemData.CNum;
                    measureItemData.PassPercent.Add(Math.Round(passRate * 100, 2).ToString());
                }
                else
                {
                    measureItemData.PassPercent.Add("");
                }
            }
        }

        /// <summary>
        /// 获取楼层级别的统计信息
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="buildingData"></param>
        /// <param name="projectName"></param>
        /// <param name="buildingName"></param>
        /// <param name="floorName"></param>
        private static void GetFloorLevelStatis(DataTable dt, BuildingData buildingData, string projectName, string buildingName, string floorName)
        {
            List<string> listHouseType = new List<string>();
            foreach (DataRow dr in dt.Rows)
            {
                string houseType = dr["HouseType"].ToString();
                if (!listHouseType.Contains(houseType))
                {
                    listHouseType.Add(houseType);
                }
            }
            //项目-楼栋-楼层
            buildingData.Unit = "户";
            foreach (string houseType in listHouseType)
            {
                DataRow[] drs = dt.Select($" FloorName='{floorName}' and BuildingName='{buildingName}' and HouseType='{houseType}'");
                if (drs != null && drs.Length > 0)
                {
                    int cNum = 0;
                    int pNum = 0;
                    buildingData.CNum = 0;
                    buildingData.PNum = 0;

                    foreach (DataRow dr in drs)
                    {
                        cNum = dr[buildingData.Code + "_C"].ToInt32();
                        pNum = dr[buildingData.Code + "_P"].ToInt32();
                        buildingData.CNum += cNum;
                        buildingData.PNum += pNum;
                    }

                    if (buildingData.CNum > 0)
                    {
                        decimal passRate = (decimal)(buildingData.CNum - buildingData.PNum) / (decimal)buildingData.CNum;
                        buildingData.PassPercent.Add(Math.Round(passRate * 100, 2).ToString());
                    }
                    else
                    {
                        buildingData.PassPercent.Add("");
                    }

                    buildingData.XAxis.Add(houseType);
                }
            }
        }

        /// <summary>
        /// 获取楼栋级别的统计信息
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="buildingData"></param>
        /// <param name="projectName"></param>
        /// <param name="buildingName"></param>
        private static void GetBuildingLevelStatis(DataTable dt, BuildingData buildingData, string projectName, string buildingName)
        {
            List<string> listFloorName = new List<string>();
            foreach (DataRow dr in dt.Rows)
            {
                string floorName = dr["FloorName"].ToString();
                if (!listFloorName.Contains(floorName))
                {
                    listFloorName.Add(floorName);
                }
            }
            //项目-楼栋-楼层
            buildingData.Unit = "层";
            foreach (string floorName in listFloorName)
            {
                DataRow[] drs = dt.Select($" ProjectName='{projectName}' and BuildingName='{buildingName}' and FloorName='{floorName}' ");
                if (drs != null && drs.Length > 0)
                {
                    int cNum = 0;
                    int pNum = 0;
                    buildingData.CNum = 0;
                    buildingData.PNum = 0;

                    foreach (DataRow dr in drs)
                    {
                        cNum = dr[buildingData.Code + "_C"].ToInt32();
                        pNum = dr[buildingData.Code + "_P"].ToInt32();
                        buildingData.CNum += cNum;
                        buildingData.PNum += pNum;
                    }

                    if (buildingData.CNum > 0)
                    {
                        decimal passRate = (decimal)(buildingData.CNum - buildingData.PNum) / (decimal)buildingData.CNum;
                        buildingData.PassPercent.Add(Math.Round(passRate * 100, 2).ToString());
                    }
                    else
                    {
                        buildingData.PassPercent.Add("");
                    }

                    buildingData.XAxis.Add(floorName);
                }
            }
        }

        /// <summary>
        /// 获取项目级别的统计信息
        /// </summary>
        /// <param name="dt"></param>
        /// <param name="buildingData"></param>
        /// <param name="projectName"></param>
        private static void GetProjectLevelStatis(DataTable dt, BuildingData buildingData, string projectName)
        {
            List<string> listBuildingName = new List<string>();
            foreach (DataRow dr in dt.Rows)
            {
                string buildingName = dr["BuildingName"].ToString();
                if (!listBuildingName.Contains(buildingName))
                {
                    listBuildingName.Add(buildingName);
                }
            }
            //项目-楼栋-楼层
            //buildingData.XAxis.AddRange(listBuildingName);
            buildingData.Unit = "栋";
            foreach (string buildingName in listBuildingName)
            {
                DataRow[] drs = dt.Select($" ProjectName='{projectName}' and BuildingName='{buildingName}'  ");
                if (drs != null && drs.Length > 0)
                {
                    int cNum = 0;
                    int pNum = 0;
                    buildingData.CNum = 0;
                    buildingData.PNum = 0;

                    foreach (DataRow dr in drs)
                    {
                        cNum = dr[buildingData.Code + "_C"].ToInt32();
                        pNum = dr[buildingData.Code + "_P"].ToInt32();
                        buildingData.CNum += cNum;
                        buildingData.PNum += pNum;
                    }

                    if (cNum > 0)
                    {
                        decimal passRate = (decimal)(buildingData.CNum - buildingData.PNum) / (decimal)buildingData.CNum;
                        buildingData.PassPercent.Add(Math.Round(passRate * 100, 2).ToString());
                    }
                    else
                    {
                        buildingData.PassPercent.Add("");
                    }

                    buildingData.XAxis.Add(buildingName);
                }
            }
        }

        /// <summary>
        /// 根据condition的非空属性查询sql
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="condition"></param>
        /// <param name="parameters"></param>
        /// <param name="sb"></param>
        private static void GetSql<T>(T condition, List<NpgsqlParameter> parameters, StringBuilder sb)
        {
            var propertys = condition.GetType().GetProperties();
            foreach (var p in propertys)
            {
                object pVal = p.GetValue(condition);
                string pName = p.Name;

                if (pName != "OrderBy")
                {
                    if (!string.IsNullOrEmpty(pVal.NullToString().Trim()) && pVal.NullToString() != Guid.Empty.ToString())
                    {
                        sb.AppendLine($" and t1.\"{pName}\" = @{pName} ");
                        parameters.Add(new NpgsqlParameter(pName, pVal));
                    }
                }
            }
        }

        /// <summary>
        /// 构造测量项
        /// </summary>
        /// <returns></returns>
        private static Dictionary<string, string> ItemDicInit()
        {
            Dictionary<string, string> dicItem = new Dictionary<string, string>();
            string itemStr = @"
                            r-chuizhidu_P 垂直度_爆点数
                            r-dimianpingzhengdu_P 地面平整度_爆点数
                            r-dimianshuipingdu_P 地面水平度_爆点数
                            r-fangzhengxing_P 方正性_爆点数
                            r-hunningtuqiangdu_P 混凝土强度_爆点数
                            r-jiemianchicun_P 截面尺寸_爆点数
                            r-kaijianjinshen_P 开间进深_爆点数
                            r-yinyang_P 阴阳角_爆点数
                            r-loubanbandishuipingdu_P 楼板板底水平度_爆点数
                            r-loubanhoudu_P 楼板厚度_爆点数
                            r-mendongchicun_P 门洞尺寸_爆点数
                            r-pingzhengdu_P 墙面平整度_爆点数
                            r-tianhuapingzhengdu_P 天花平整度_爆点数
                            r-waichuangdongkouchicun_P 外窗洞口尺寸_爆点数
                            r-waichuangneiceqiangtihoudujicha_P 外窗内侧墙体厚度极差_爆点数
                            r-tijiaoxianpingzhengdu 踢脚线平整度
                            r-mentaoxianchuizhidu 门套线垂直度
                            r-mentaoxianpingzhengdu 门套线平整度
                            r-yinyangjiaozhixiandu 阴阳角直线度";

            var itemArr = itemStr.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string item in itemArr)
            {
                string itemText = item.Trim();
                var arr = itemText.Split(' ', StringSplitOptions.RemoveEmptyEntries);
                string itemKey = arr[0];
                string itemName = arr[1];
                itemKey = itemKey.Replace("_P", string.Empty);
                itemName = itemName.Replace("_爆点数", string.Empty);
                if (!dicItem.ContainsKey(itemKey))
                {
                    dicItem.Add(itemKey, itemName);
                }
            }
            return dicItem;
        }

        /// <summary>
        /// 获取测量项信息
        /// </summary>
        public readonly Dictionary<string, string> GetDicItem = ItemDicInit();

        /// <summary>
        /// 获取用户可以查询工效的项目sql
        /// </summary>
        /// <param name="tableAlis"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public async ValueTask<string> GetRelationProjectsSql(string tableAlis, string field)
        {
            string sql = string.Empty;
            Guid companyId = Guid.Empty;
            if (OperatorProvider.Get().RoleNameList == "公司管理员")
            {
                companyId = OperatorProvider.Get().CompanyGuid;
            }
            var list = await GetRelationProjectsWithCompany(OperatorProvider.Get().Id, companyId);
            if (list != null && list.Count > 0)
            {
                sql = $@" and {tableAlis}.""{field}"" in ({string.Join(',', list.Select(p => $"'{p.ProjectId}'"))})";
            }
            else
                sql = $@" and {tableAlis}.""{field}"" = '{Guid.Empty}' ";

            return sql;
        }

        /// <summary>
        /// 获取用户可以查询工效的项目
        /// </summary>
        /// <param name="userId"></param>
        /// <param name="companyId"></param>
        /// <returns></returns>
        private async Task<List<ProjectIdDto>> GetRelationProjectsWithCompany(Guid userId, Guid companyId)
        {
            List<ProjectIdDto> list = new List<ProjectIdDto>();
            List<NpgsqlParameter> paras = new List<NpgsqlParameter>()
            {
                new NpgsqlParameter("@YunUserGuid", userId),
                new NpgsqlParameter("@CompanyGuid", companyId)
            };
            string sql = string.Empty;
            if (companyId == Guid.Empty)
            {
                sql = string.Format(VisionCloudGlobalContext.GetSection("sqls:sql:query_relation_projects_with_company01"));
            }
            else
            {
                sql = string.Format(VisionCloudGlobalContext.GetSection("sqls:sql:query_relation_projects_with_company02"));
            }
            list = await PgSqlHelper.QueryListAsync<ProjectIdDto>(sql, paras.ToArray());

            return list;
        }

        /// <summary>
        /// 生成六位随机数
        /// </summary>
        /// <returns></returns>
        public static string GetRandomNumber()
        {
            Random ro = new Random();
            int iResult;
            int iUp = 99999;
            int iDown = 00000;
            iResult = ro.Next(iDown, iUp);
            return iResult.ToString().Trim();
        }
    }
}